package com.woniu.rabbitMq.config;

import com.woniu.rabbitMq.entity.FailMessage;
import com.woniu.rabbitMq.service.FailMessageService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;

/**
 * 生产者的可靠投递
 */
@Configuration
public class RabbitCallbackConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private FailMessageService messageService;

    /**
     * 注解初始化
     */
    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
        rabbitTemplate.setMandatory(true);
    }

    /**
     * 消息从生产者到交换机确认（只要发送消息就会回调）
     *
     * @param correlationData correlation data for the callback.
     *                        amqp依赖没有创建相应对象，需要开发人员手动添加
     * @param ack             true for ack, false for nack
     * @param cause           An optional cause, for nack, when available, otherwise null.
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            return;
        }
        // 获取发消息前填入的参数
        byte[] messageByte = correlationData.getReturnedMessage().getBody();
        String receivedExchange = correlationData.getReturnedMessage().getMessageProperties().getReceivedExchange();
        String receivedRoutingKey = correlationData.getReturnedMessage().getMessageProperties().getReceivedRoutingKey();

        // 消息id
        String appId = correlationData.getReturnedMessage().getMessageProperties().getAppId();

        FailMessage message;
        if (!StringUtils.isEmpty(appId)) {
            // 存在更新状态为2
            message = messageService.getById(appId);
            message.setState(2);
            message.setCount(message.getCount() + 1);
        } else {
            message = new FailMessage();
            message.setMessage(new String(messageByte));
            message.setExchange(receivedExchange);
            message.setRoutingKey(receivedRoutingKey);
        }
        messageService.saveOrUpdate(message);
    }

    /**
     * 消息从交换机到队列失败（失败才会回调）
     *
     * @param message    the returned message.
     * @param replyCode  the reply code.
     * @param replyText  the reply text.
     * @param exchange   the exchange.
     * @param routingKey the routing key.
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        String appId = message.getMessageProperties().getAppId();

        FailMessage msg;
        // 从数据库查找看有没有对应失败的信息，有就更新状态为2失败
        if (!StringUtils.isEmpty(appId)) {
            // 更改消息状态为2，失败
            msg = messageService.getById(appId);
            msg.setState(2);
            msg.setCount(msg.getCount() + 1);
        } else {
            msg = new FailMessage();
            msg.setMessage(new String(message.getBody()));
            msg.setExchange(exchange);
            msg.setRoutingKey(routingKey);
        }
        messageService.saveOrUpdate(msg);
    }
}
